1. 為什麼需要進階錯誤處理
昨天的小專案已經用過 Result 來避免程式崩潰,但那只是基本應用。今天我想更深入了解在不同錯誤情境下,該怎麼區分可恢復與不可恢復的情況。
2. panic!:當程式無法繼續執行時
panic! 會立即終止程式,並印出錯誤訊息與堆疊追蹤(stack trace)。
fn main() {
let v = vec![1, 2, 3];
println!("{}", v[99]); // 超出範圍
}
輸出:
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', src/main.rs:2:20
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
這種情況屬於程式邏輯錯誤(邏輯上應該不會發生,這類錯誤通常是開發階段就應該被修正的,不屬於使用者輸入錯誤),因此用 panic 結束是合理的。
3. 手動使用 panic!
當發現明顯錯誤時也能主動觸發 panic:
fn divide(a: i32, b: i32) -> i32 {
if b == 0 {
panic!("Cannot divide by zero!");
}
a / b
}
fn main() {
divide(10, 0);
}
輸出:
thread 'main' panicked at 'Cannot divide by zero!', src/main.rs:3:9
4. Result 與 ? 運算子
Result<T, E> 是 Rust 中更常見的錯誤處理方式,用來代表「可能成功或失敗」。
? 可自動傳遞錯誤,讓程式更簡潔:
use std::fs::File;
use std::io::{self, Read};
fn read_file() -> Result<String, io::Error> {
let mut file = File::open("text.txt")?; // 若錯誤,會自動 return Err(e)
let mut content = String::new();
file.read_to_string(&mut content)?;
Ok(content)
}
fn main() {
match read_file() {
Ok(text) => println!("{}", text),
Err(e) => println!("Error: {}", e),
}
}
5. panic! vs Result:何時該用哪一種?
程式邏輯錯誤、無法恢復的情況(例如:除以 0、越界、程式錯誤) 則使用panic!
可預期錯誤、能讓使用者修正(例如:讀檔失敗、網路中斷) 則使用Result
6.學習心得與補充
今天的學習讓我更清楚地理解了 Rust 的錯誤處理邏輯。以前在寫 C++ 時,如果遇到除以零或開檔失敗的情況,通常只會回傳一個錯誤碼或直接當掉,但在 Rust 中,我必須明確選擇是用 Result 處理、還是直接用 panic! 結束,這讓我更主動地面對錯誤。尤其是 ? 運算子真的很好用,它讓錯誤傳遞的程式碼變得簡潔又清楚,整體看起來乾淨許多。